import time, os, sys, network, socket, ustruct
from media.vencoder import *
from media.sensor import *
from media.display import *
from media.media import *

class CameraStreamer:
    _DEFAULT_CONFIG = {
            "ip": "192.168.137.1",
            "port": 6001,
            "ssid": "Ciallo～(∠・ω< )⌒☆",
            "pwd": "0d000721",
            "w": 1280,
            "h": 720,
            "chn": CAM_CHN_ID_2,
            "chunk_size": 65535,
            "timeout": 15,
            "tcp_reconnect": 500
    }
    sock = None
    streamData = StreamData()
    tcp_connect_t = time.ticks_ms()
    tcp_connect = False
    def __init__(self, ip = "192.168.137.1", port = 6001, ssid = "Ciallo～(∠・ω< )⌒☆", pwd = "0d000721", w = 1280, h = 720, sensor = None):
        self.cfg = CameraStreamer._DEFAULT_CONFIG.copy()

        self.cfg["ip"] = ip
        self.cfg["port"] = port
        self.cfg["ssid"] = ssid
        self.cfg["pwd"] = pwd
        self.cfg["w"] = w
        self.cfg["h"] = h
        #self.cfg["chn"] = VENC_CHN_ID_0
        #self.cfg["chunk_size"] = 65535
        #self.cfg["timeout"] = 15
        #self.cfg["tcp_reconnect"] = 500

        if sensor:
            sensor.set_framesize(chn=self.cfg["chn"], width=1280, height=720)
            sensor.set_pixformat(chn=self.cfg["chn"], pix_format=Sensor.YUV420SP)
            link = MediaManager.link(
                sensor.bind_info(chn=self.cfg["chn"])['src'],
                (VIDEO_ENCODE_MOD_ID, VENC_DEV_ID, VENC_CHN_ID_0)
            )
        # 初始化编码器
        self.encoder = Encoder()
        # 配置H265编码参数
        self.encoder.SetOutBufs(chn=VENC_CHN_ID_0, buf_num=8, width=self.cfg["w"], height=self.cfg["h"])
        self.chnAttr = ChnAttrStr(
            self.encoder.PAYLOAD_TYPE_H265,
            self.encoder.H265_PROFILE_MAIN,
            self.cfg["w"],
            self.cfg["h"]
        )

    def start(self):
        if not self.connect_wifi():
            return
        self.encoder.Create(VENC_CHN_ID_0, self.chnAttr)
        self.encoder.Start(VENC_CHN_ID_0)

    def deint(self):
        self.encoder.Stop(VENC_CHN_ID_0)
        self.encoder.Destroy(VENC_CHN_ID_0)
        self.close_tcp()

    def check(self):
        if not self.tcp_connect:
            if time.ticks_diff(time.ticks_ms(), self.tcp_connect_t) > self.cfg["tcp_reconnect"]:
                self.tcp_connect_t = time.ticks_ms()
                self.tcp_connect = self.connect_tcp()
            else:
                print("n tcp")
                return
        self.encoder.GetStream(VENC_CHN_ID_0, self.streamData)
        if not self.send_h265_frame(self.streamData):
            self.close_tcp()
        self.encoder.ReleaseStream(VENC_CHN_ID_0, self.streamData)

    def connect_wifi(self):
        wlan = network.WLAN(network.STA_IF)
        wlan.active(True)
        if not wlan.isconnected():
            print(f"正在连接 {self.cfg["ssid"]}...")
            wlan.connect(self.cfg["ssid"], self.cfg["pwd"])
            start = time.ticks_ms()
            while not wlan.isconnected():
                if time.ticks_diff(time.ticks_ms(), start) > self.cfg["timeout"]*1000:
                    print("错误: WiFi连接超时")
                    return False
                time.sleep_ms(100)
        ip = wlan.ifconfig()[0]
        while ip == "0.0.0.0":
            ip = wlan.ifconfig()[0]
        print(f"WiFi已连接 IP:{ip}")
        return True

    def connect_tcp(self) -> bool:
        if self.sock:
            return True
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        #self.sock.setblocking(False)
        addr = socket.getaddrinfo(self.cfg["ip"], self.cfg["port"])[0][-1]
        try:
            self.sock.connect(addr)
            print(f"已连接服务器 {self.cfg["ip"]}:{self.cfg["port"]}")
            self.send_title()
            return True
        except Exception as e:
            print(f"连接失败: {e}")
            return False

    def close_tcp(self):
        if self.sock:
            self.sock.close()
            self.sock = None

    def send_title(self):
        config_header = ustruct.pack("<LLL", 0xFFFFFFFF, self.cfg["w"], self.cfg["h"])
        sent = 0
        while sent < 6:
            sent += self.sock.send(config_header[sent:])
            os.exitpoint()

    def send_h265_frame(self, streamData):
        total_size = sum(4 + streamData.data_size[i] for i in range(streamData.pack_cnt))
        nalu_count = streamData.pack_cnt
        header = ustruct.pack("<LL", total_size, nalu_count)

        # 构建合并的数据缓冲区
        data_buffer = bytearray()
        for i in range(nalu_count):
            nalu_size = streamData.data_size[i]
            data_buffer += ustruct.pack("<L", nalu_size)
            nalu_data = uctypes.bytearray_at(streamData.data[i], nalu_size)
            data_buffer.extend(nalu_data)

        # 发送包头和合并数据
        self.sock.send(header)
        total_sent = 0
        while total_sent < len(data_buffer):
            sent = self.sock.send(data_buffer[total_sent:total_sent+self.cfg["chunk_size"]])
            if sent == 0:
                raise RuntimeError("连接中断")
                break
            total_sent += sent
        return True

def camera_stream():
    sensor = Sensor(id=2)
    i = CameraStreamer(ip = "192.168.137.1", port = 6001, ssid = "Ciallo～(∠・ω< )⌒☆", pwd = "0d000721", w = 1280, h = 720, sensor=sensor);
    MediaManager.init()
    i.start()
    sensor.run()
    try:
        while 1:
            # 获取编码数据
            i.check()
            os.exitpoint()
    except Exception as e:
        print(f"主循环异常：{e}")
    finally:
        sensor.stop()
        i.deint()
        MediaManager.deinit()

if __name__ == "__main__":
    camera_stream()
